package common.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.aspose.words.Shape;
import com.aspose.words.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.yuntsg.ruiijn.databse_search.entity.FileDetails;
import com.yuntsg.ruiijn.paperana.utils.StrUtils;
import common.extractText.Change;
import common.vo.Scenario;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.support.RequestContext;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.*;
import java.util.regex.Pattern;

import static common.util.PdfUtil.ensureOpaque;
import static common.util.VerifyUtil.isServer;

@SuppressWarnings("all")
@Component
@Slf4j
public class ExtractUtil {

    @Autowired
    private MinioUtil minioUtil;

    @Value("${upload.tempPath}")
    public String tempPath;

    public static boolean getLicenseStatic() {
        boolean result = false;
        try {
//            String PATH = "/data/analysis/WEB-INF/classes/license.xml";
            String PATH = getPathStat() + "WEB-INF/classes/license.xml";
            if (FileUtil.exist(PATH)) {
                log.info("word licence  存在");
            }
            log.info("当前项目路径++" + getPathStat());
            if (!isServer()) {
                log.info("是我本机测试");
                // F:\qfworkspace\idea\article_analysis_local\src\main\resources
                PATH = getPathStat() + "\\src\\main\\resources\\license.xml";
            }
            InputStream license = new ByteArrayInputStream(FileUtil.readBytes(PATH));
            License aposeLic = new License();
            aposeLic.setLicense(license);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //本地word 测试
    public static boolean getLocalLicense() {
        boolean result = false;
        try {
            InputStream license = new FileInputStream(common.util.FileUtil.getWriteFilePath() + "license.xml");
            License aposeLic = new License();
            aposeLic.setLicense(license);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static List<String> dealPdfToText(List<String> strs) {
        List<String> res = new ArrayList<>(1000000);
        for (String str : strs) {
            if (str.contains("。")) {
                String[] split = str.split("。");
                for (String s : split) {
                    res.add(s + "。");
                }
            } else {
                if (StringUtil.isNotNull(str)) {
                    res.add(str);
                }

            }

        }
        return res;
    }

    public static List<String> spaceEnd(Set<String> filterSet, List<String> strings) {
        List<String> lines = new ArrayList<>();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < strings.size(); i++) {
            String string = strings.get(i);
            if (isContains(filterSet, string)) {
                continue;
            }

            if (isUrl(string)) {
                continue;
            }

            if (isReferences(string)) {
                break;
            }

            if (isFirstNumStr(string)) {
                if (stringBuilder.length() > 0) {
                    lines.add(stringBuilder.toString().trim());
                }
                stringBuilder = new StringBuilder();
            }

            if (isUpStr(string)) {
                if (stringBuilder.length() > 0) {
                    lines.add(stringBuilder.toString().trim());
                }
                lines.add(string.trim());
                stringBuilder = new StringBuilder();
                continue;
            }

            if (string.endsWith("-")) {
                stringBuilder.append(string.trim(), 0, string.trim().length() - 1);
                Integer num = 0;
                for (int s = 1; s <= 20; s++) {
                    if (strings.size() > i + s && strings.get(i + s).trim().equals("")) {
                        num++;
                    } else {
                        break;
                    }
                }
                i = i + num;
            } else if (string.endsWith(" ")) {
                stringBuilder.append(string.trim() + " ");
                Integer num = 0;
                for (int s = 1; s <= 20; s++) {
                    if (strings.size() > i + s && strings.get(i + s).trim().equals("")) {
                        num++;
                    } else {
                        break;
                    }
                }
                i = i + num;
            } else if (string.trim().equals("")) {
                if (stringBuilder.length() > 0) {
                    lines.add(stringBuilder.toString());
                }
                stringBuilder = new StringBuilder();
            } else {
                stringBuilder.append(string.trim());
            }
        }
        if (stringBuilder.length() > 0) {
            lines.add(stringBuilder.toString().trim());
        }

        return lines;
    }

    public static List<String> commonSplit(Set<String> filterSet, List<String> strings) {
        List<String> lines = new ArrayList<>();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < strings.size(); i++) {
            String string = strings.get(i);
            if (isContains(filterSet, string)) {
                continue;
            }

            if (isUrl(string)) {
                continue;
            }

            if (isReferences(string)) {
                break;
            }

            if (isFirstNumStr(string)) {
                if (stringBuilder.length() > 0) {
                    lines.add(stringBuilder.toString().trim());
                }
                stringBuilder = new StringBuilder();
            }

            if (isUpStr(string)) {
                if (stringBuilder.length() > 0) {
                    lines.add(stringBuilder.toString().trim());
                }
                lines.add(string.trim());
                stringBuilder = new StringBuilder();
                continue;
            }

            if (string.endsWith("-")) {
                stringBuilder.append(string.trim(), 0, string.trim().length() - 1);
                Integer num = 0;
                for (int s = 1; s <= 20; s++) {
                    if (strings.size() > i + s && strings.get(i + s).trim().equals("")) {
                        num++;
                    } else {
                        break;
                    }
                }
                i = i + num;
                continue;
            } else if (!string.trim().equals("")) {
                stringBuilder.append(string.trim() + " ");
            }

            if (isEnd(string)) {
                if (stringBuilder.length() > 0) {
                    lines.add(stringBuilder.toString());
                }
                stringBuilder = new StringBuilder();
            }
        }


        return lines;

    }

    public static Boolean isUpStr(String str) {
        str = str.trim();
        return Pattern.compile("^[A-Z]+$").matcher(str).find();
    }

    public static Boolean isFirstNumStr(String str) {
        str = str.trim().replace(" ", "");
        boolean b1 = Pattern.compile("^[0-9]+\\.").matcher(str).find();
        if (b1) {
            return true;
        }
        boolean b2 = Pattern.compile("^\\([0-9]+\\)").matcher(str).find();
        if (b2) {
            return true;
        }
        return Pattern.compile("^\\[[0-9]+\\]").matcher(str).find();
    }

    public static Boolean isUrl(String str) {
        return (str.contains("http://") || str.contains("https://"));
    }

    public static Boolean isReferences(String str) {
        return (str.trim().equalsIgnoreCase("references") || (str.trim().toLowerCase().startsWith("references") && str.trim().length() < 20));
    }

    public static Boolean isContains(Set<String> filter, String str) {
        if (str.length() > 0 && filter.contains(str)) {
            return true;
        }
        return false;
    }

    public static Boolean isEnd(String str) {
        str = str.trim();
        boolean end1 = Pattern.compile("(\\.|;|!|;|\\?$)").matcher(str).find();

        if (end1) {
            return true;
        }

        str = str.replace("[", "").replace("]", "").replace(",", "").replace(" ", "");

        boolean end2 = Pattern.compile("(\\.|!|\\?|;)[0-9]+$").matcher(str).find();
        return end2;

    }

//    private static String getPathStatic() {
//        //服务器: tomcat/webapps/root
//        //windows: 工作路径/项目名
//        try {
//            String root = RequestContext.class.getResource("/").getFile();
//            String a = new File(root).getParentFile().getParentFile().getCanonicalPath();
//            if (StringUtil.isNotNull(a) && a.equals("/")) {
//                String path = "/data/analysis/WEB-INF/classes/";
//                return path;
//            } else {
//                return a;
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//
//        return null;
//    }

    private static String getPathStat() {
        //服务器: tomcat/webapps/root
        //windows: 工作路径/项目名
        try {
            String root = RequestContext.class.getResource("/").getFile();
            String a = new File(root).getParentFile().getParentFile().getCanonicalPath();

            if (!a.endsWith("/")) {
                a = a + "/";
            }
            log.info("aaaapath++" + a);
            return a;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    private String getPath() {
        //服务器: tomcat/webapps/root
        //windows: 工作路径/项目名
        try {
            String root = RequestContext.class.getResource("/").getFile();
            String a = new File(root).getParentFile().getParentFile().getCanonicalPath();
            if (StringUtil.isNotNull(a) && a.equals("/")) {
                String path = this.getClass().getClassLoader().getResource("").getPath();
                log.info("path++" + path);
                if (!path.endsWith("/")) {
                    path = path + "/";
                }
                return path;
            } else {

                if (!a.endsWith("/")) {
                    a = a + "/";
                }
                log.info("aaaapath++" + a);
                return a;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 提取段落txt
     *
     * @param inputStream
     * @param rid
     * @param userId
     * @return
     * @throws Exception
     */
    public List<FileDetails> extract0(Integer rid, Integer userId, String path) throws Exception {
        List<FileDetails> fileDetailsArr = new ArrayList<FileDetails>();
        List<String> strList = FileUtil.readLines(path, Charset.defaultCharset());
        List<Change.TableField> ex = Change.ex(strList);
        for (Change.TableField tableField : ex) {
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFId(rid);
            fileDetails.setTpye(1);
            fileDetails.setParagraphName(tableField.getParagraph_name());
            fileDetails.setSubProject(tableField.getSub_project());
            fileDetails.setSegment(tableField.getParagraph());
            fileDetails.setSentence(tableField.getSentence());
            // 如果这里 动态匹配会不会影响入库时间, 直接在先获取吧 要不这里如果一个大文本入库容易卡时间
            fileDetails.setTxtContent(tableField.getStr());
            fileDetailsArr.add(fileDetails);
        }

        return fileDetailsArr;
    }

    /**
     * 利用pdfbox提取图片
     */
    public List<FileDetails> extractPdfBox(Integer rid, Integer userId, String path) throws Exception {
        List<FileDetails> fileDetailsArr = new ArrayList<FileDetails>();
        PDDocument doc = Loader.loadPDF(minioUtil.downloadByte(path));
        Iterator<PDPage> iter = doc.getDocumentCatalog().getPages().iterator();
        int count = 0;
        while (iter.hasNext()) {
            PDPage page = iter.next();
            PDResources resources = page.getResources();
            for (COSName cosName : resources.getXObjectNames()) {//遍历单页内对象
                if (resources.isImageXObject(cosName)) {//图片对象
                    PDImageXObject imageXObject = (PDImageXObject) resources.getXObject(cosName);
                    BufferedImage image = imageXObject.getImage();
                    FileDetails fileDetails = new FileDetails();
                    fileDetails.setFId(rid);
                    fileDetails.setTpye(2);
                    String name = RandomUtil.randomString(8) + ".jpg";
                    String jpg = "";
                    if (image.getHeight() > 2000 || image.getWidth() > 2000) {
                        Image img = ImgUtil.scale(image, 0.4f);
                        jpg = minioUtil.upload(ImgUtil.toStream(img, "jpg"), userId, DateUtil.today(), name, Scenario.view);
                    } else {
                        jpg = minioUtil.upload(bufferedImageToInputStream(image), userId, DateUtil.today(), name, Scenario.view);
                    }
                    if (null != jpg && StrUtil.isNotEmpty(jpg)) {
                        fileDetails.setPath(jpg);
                    } else {
                        continue;
                    }
                    fileDetailsArr.add(fileDetails);
                    count++;
                }
            }
        }
        doc.close();
        return fileDetailsArr;
    }

    /**
     * 整页拆分
     *
     * @param rid
     * @param userId
     * @param path
     * @return
     * @throws Exception
     */
    public List<FileDetails> extractPdfBoxForFull(Integer rid, Integer userId, String path) throws Exception {
        List<FileDetails> fileDetailsArr = new ArrayList<FileDetails>();
        PDDocument doc = Loader.loadPDF(minioUtil.downloadByte(path));
        PDFRenderer renderer = new PDFRenderer(doc);
        int pageCount = doc.getNumberOfPages();
        for (int i = 0; i < pageCount; i++) {
            BufferedImage image = renderer.renderImageWithDPI(i, 144);
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFId(rid);
            fileDetails.setTpye(2);
            String name = RandomUtil.randomString(8) + ".jpg";
            String jpg = "";
            if (image.getHeight() > 2000 || image.getWidth() > 2000) {
                Image img = ImgUtil.scale(image, 0.4f);
                jpg = minioUtil.upload(ImgUtil.toStream(img, "jpg"), userId, DateUtil.today(), name, Scenario.view);
            } else {
                jpg = minioUtil.upload(bufferedImageToInputStream(image), userId, DateUtil.today(), name, Scenario.view);
            }
            if (null != jpg && StrUtil.isNotEmpty(jpg)) {
                fileDetails.setPath(jpg);
            } else {
                continue;
            }
            fileDetailsArr.add(fileDetails);
        }
        doc.close();
        return fileDetailsArr;
    }

    /**
     * 将BufferedImage转换为InputStream
     *
     * @param image
     * @return
     */
    public InputStream bufferedImageToInputStream(BufferedImage image) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
            InputStream input = new ByteArrayInputStream(os.toByteArray());
            return input;
        } catch (IOException e) {

        }
        return null;
    }

    public BufferedImage Mat2BufferedImage(Mat mat) throws IOException {
        //编码图像
        MatOfByte matOfByte = new MatOfByte();
        Imgcodecs.imencode(".jpg", mat, matOfByte);
        //将编码的Mat存储在字节数组中
        byte[] byteArray = matOfByte.toArray();
        //准备缓冲图像
        InputStream in = new ByteArrayInputStream(byteArray);
        BufferedImage bufImage = ImageIO.read(in);
        return bufImage;
    }

    public Image byteArrayToImage(byte[] byteArrayIn) {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(byteArrayIn);
            BufferedImage read = ImageIO.read(bais);
            return read;
        } catch (Exception e) {
            System.out.println("图片转换失败");
        }
        return null;
    }

    /**
     * 提取段落 doc
     *
     * @param inputStream
     * @param rid
     */
    public List<FileDetails> extractWord(InputStream inputStream, Integer rid, Integer userId) throws Exception {
        getLicense();
        Document doc = null;
        try {
            doc = new Document(inputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        SectionCollection sections = doc.getSections();

        List<FileDetails> fileDetailsArr = new ArrayList<FileDetails>();
        StringBuffer bf = new StringBuffer();


        for (Section section : sections) {
            ParagraphCollection paragraphs = section.getBody().getParagraphs();
            for (Paragraph paragraph : paragraphs) {
                String text = paragraph.getRange().getText();
                bf.append(text);
            }
        }

        List<TableField> tableList = new ArrayList<>();
//        List<String> strList = Arrays.asList(bf.toString().split("\n"));
        //2023年10月7日15:59:07 换行符是/r 如果是/n 拆不出句子
        List<String> strList = Arrays.asList(bf.toString().split("\r"));
        List<Change.TableField> ex = Change.ex(strList);
        for (Change.TableField tableField : ex) {
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFId(rid);
            fileDetails.setTpye(1);
            fileDetails.setParagraphName(tableField.getParagraph_name());
            fileDetails.setSubProject(tableField.getSub_project());
            fileDetails.setSegment(tableField.getParagraph());
            fileDetails.setSentence(tableField.getSentence());
            // 如果这里 动态匹配会不会影响入库时间, 直接在先获取吧 要不这里如果一个大文本入库容易卡时间
            fileDetails.setTxtContent(tableField.getStr());
            fileDetailsArr.add(fileDetails);
        }

        int imageIndex = 0;
        NodeCollection shapes = doc.getChildNodes(NodeType.SHAPE, true);
        for (Shape shape : (Iterable<Shape>) shapes) {
            if (shape.hasImage()) {
                String imageFileName = null;
                FileDetails fileDetailsSelf = new FileDetails();
                fileDetailsSelf.setFId(rid);
                fileDetailsSelf.setTpye(2);
                String jpg = null;
                String name = null;
                if (shape.getImageData().getImageType() == 1) {
                    name = RandomUtil.randomString(8) + ".emf";
                } else {
                    name = RandomUtil.randomString(8) + FileFormatUtil.imageTypeToExtension(shape.getImageData().getImageType());
                }
                boolean scale = false;
                if (shape.getImageData().getImageSize().getHeightPixels() > 2000 || shape.getImageData().getImageSize().getWidthPixels() > 2000) {
                    scale = true;
                }
                if (name.endsWith(".emf")) {
                    shape.getImageData().save(tempPath + name);
                    InputStream stream = PdfUtil.convertEmf(tempPath, name, scale);
                    if (null == stream) {
                        continue;
                    }
                    jpg = minioUtil.upload(stream, userId, DateUtil.today(), name.replace("emf", "jpg"), Scenario.view);
                } else {
                    if (scale) {
                        String af = FileFormatUtil.imageTypeToExtension(shape.getImageData().getImageType());
                        Image img = ImgUtil.scale(shape.getImageData().toImage(), 0.4f);
                        jpg = minioUtil.upload(ImgUtil.toStream(img, af.replace(".", "")), userId, DateUtil.today(), name, Scenario.view);
                    }
                    jpg = minioUtil.upload(shape.getImageData().toStream(), userId, DateUtil.today(), name, Scenario.view);
                }

                if (null != jpg && StrUtil.isNotEmpty(jpg)) {
                    fileDetailsSelf.setPath(jpg);
                } else {
                    continue;
                }
                fileDetailsArr.add(fileDetailsSelf);
                imageIndex++;
            }
        }
        return fileDetailsArr;
    }

    public boolean getLicense() {
        boolean result = false;
        try {
            String PATH = "/data/analysis/license.xml";
            log.info("当前项目路径++" + getPath());
            if (!isServer()) {
                // F:\qfworkspace\idea\article_analysis_local\src\main\resources
                PATH = getPath() + "\\src\\main\\resources\\license.xml";
            }
            InputStream license = new ByteArrayInputStream(FileUtil.readBytes(PATH));
            License aposeLic = new License();
            aposeLic.setLicense(license);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public List<FileDetails> extractPdf(InputStream inputStream, Integer rid, Integer userId) throws IOException {
        List<FileDetails> fileDetailsSelfs = new ArrayList<FileDetails>();

        String formatStr = tempPath + "{}/{}/{}/";
        String path = StrUtil.format(formatStr, userId, DateUtil.now(), RandomUtil.randomString(4));
        String tempName = RandomUtil.randomString(5) + ".pdf";
        FileUtil.writeFromStream(inputStream, path + tempName);
        List<String> text = PdfUtil.pdfToTxt(path, path + tempName);
        //  预处理 有的语句是中文需要进行准确切分 2024年8月13日20:03:58
        text = dealPdfToText(text);
        List<ImageInfo> imageInfos = PdfUtil.pdftoImages(path, path + tempName);
        for (ImageInfo imageInfo : imageInfos) {
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFId(rid);
            fileDetails.setTpye(2);
            String name = imageInfo.getName();
            BufferedImage image = ImgUtil.read(new ByteArrayInputStream(imageInfo.getBytes()));
            String jpg = "";

            Integer height = 0;
            Integer width = 0;
            if (image.getHeight() > image.getWidth()) {
                height = 2000;
                width = Convert.toInt(image.getWidth() / (Convert.toDouble(image.getHeight()) / 2000));
                if (width == 0) {
                    continue;
                }
            } else {
                width = 2000;
                height = Convert.toInt(image.getHeight() / (Convert.toDouble(image.getWidth()) / 2000));
                if (height == 0) {
                    continue;
                }
            }


            BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics2D = scaledImage.createGraphics();
            graphics2D.drawImage(image, 0, 0, width, height, null);
            graphics2D.dispose();

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ImageIO.write(ensureOpaque(image), "jpg", bos);
            bos.flush();
            jpg = minioUtil.upload(new ByteArrayInputStream(bos.toByteArray()), userId, DateUtil.today(), name, Scenario.view);
            bos.close();

            if (null != jpg && StrUtil.isNotEmpty(jpg)) {
                fileDetails.setPath(jpg);
            } else {
                continue;
            }
            fileDetailsSelfs.add(fileDetails);
        }

        List<Change.TableField> ex = new ArrayList<>();
        if (StrUtils.isRuiJin()) {
            ex = Change.exRuijin(text);
        } else {
            ex = Change.ex(text);
        }

        for (Change.TableField tableField : ex) {
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFId(rid);
            fileDetails.setTpye(1);
//            fileDetails.setParagraphName(tableField.getParagraph_name());
//            fileDetails.setSubProject(tableField.getSub_project());
            fileDetails.setSegment(tableField.getParagraph());
            fileDetails.setSentence(tableField.getSentence());
            // 如果这里 动态匹配会不会影响入库时间, 直接在先获取吧 要不这里如果一个大文本入库容易卡时间 2023年10月5日15:00:17
            fileDetails.setTxtContent(tableField.getStr());
            fileDetailsSelfs.add(fileDetails);
        }
        try {
            FileUtil.del(path);
        } catch (Exception e) {

        }
        return fileDetailsSelfs;
    }


}
